﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;


namespace Confessor
{
    public partial class FormConfessor : Form
    {
        xFileActions xFA;
        Interrogation interrogation;
        ScanObject scanObject;
        xRegEx xRegEx;
        List<ScanErrorObject> scanErrorsList;

        // Default form initialize constructor.
        public FormConfessor()
        {
            InitializeComponent();
            xFA = new xFileActions();
            xRegEx = new xRegEx();
            interrogation = new Interrogation();
            scanObject = new ScanObject();
            scanErrorsList = new List<ScanErrorObject>();

            #region ToolTip Code
            // Create the ToolTip and associate with the Form container.
            ToolTip toolTip1 = new ToolTip();

            // Set up the delays for the ToolTip.
            toolTip1.AutoPopDelay = 5000;
            toolTip1.InitialDelay = 1000;
            toolTip1.ReshowDelay = 1000;

            // Force the ToolTip text to be displayed whether or not the form is active.
            toolTip1.ShowAlways = true;

            // Set up the ToolTip text for the form items.
            toolTip1.SetToolTip(this.textBoxInvestigationID, @"This is the name of the Confession, be sure the name follows file naming conventions as it is also used as the name of the results directory");
            toolTip1.SetToolTip(this.textBoxToolsShare, @"Location of the tools required to run Confessor. This can be either a UNC Path \\server\share or a local directory c:\confessor\tools  See confessor document for list of executables needed.  http://confessor.codeplex.com");
            toolTip1.SetToolTip(this.textBoxResultsShare, @"Location of the directory where results will be saved.  This can be either a UNC Path \\server\share or a local directory c:\confessor\results.  Confessor will create a sub-directory with the InvestigationID where all results for the confession will be placed.");
            toolTip1.SetToolTip(this.textBoxUserName, @"Domain\Username or just Username of the account to be used for authentication.");
            toolTip1.SetToolTip(this.buttonFileUpload, @"Upload a file of either comma seperated IP's/hostnames or with each ip/hostname benig on it's own line");
            toolTip1.SetToolTip(this.checkBoxWMIShares, @"This confession method will use WMI for executing the confession. No files will be copied to the remote host. If using this method for Confession, both the results and tool paths must be a share. See Confessor documentation @ http://confessor.codeplex.com");
            toolTip1.SetToolTip(this.checkBoxWMIFileCopy, @"This confession method will map a drive to the target host, copy over key files used in the confession and then execute the confession via WMI.");
            toolTip1.SetToolTip(this.checkBoxPSExec, @"This confession method uses PSExec to execute the confession on the remote host.  The files are copied via a mapped network drive to the target.");
            toolTip1.SetToolTip(this.checkBoxPSExecAsSystem, @"This confession method uses PSExec as System (on remote host) to execute the confession on the remote host.  The files are copied via a mapped network drive to the target.");
            toolTip1.SetToolTip(this.numericUpDownMinutesPerHost, @"This represents the number of minutes confessor allots to a host before flagging it as failed and moving on to the next.");
            toolTip1.SetToolTip(this.buttonDGIPs, @"After entering in an IP or Hostname in the TargetHosts list to the left, you must click this button to add them to the scan.");
            toolTip1.SetToolTip(this.textBoxRegKey1, @"Full Reg Key path for the first user defined key value.  Must also check at least one of the RegKey: checkboxes");
            toolTip1.SetToolTip(this.textBoxRegKey2, @"Full Reg Key path for the second user defined key value.  Must also check at least one of the RegKey: checkboxes");
            toolTip1.SetToolTip(this.textBoxRegKey3, @"Full Reg Key path for the third user defined key value.  Must also check at least one of the RegKey: checkboxes");
            toolTip1.SetToolTip(this.checkBoxRegKeyValues, @"If the regkey exists will list the values for the identified reg keys.  Full path to the regkey must be entered. example: hkcu\microsoft\windows\currentversion\run");
            toolTip1.SetToolTip(this.checkBoxRegKeyCopy, @"Will copy the existing registry key to the results directory as regkey1.reg, regkey2.reg or regkey3.reg");
            toolTip1.SetToolTip(this.textBoxFileExists1, @"Full file path to file (c:\windows\system32\somefile.dll) and then one of the File: checkboxes must be checked.");
            toolTip1.SetToolTip(this.textBoxFileExists2, @"Full file path to file (c:\windows\system32\somefile.dll) and then one of the File: checkboxes must be checked.");
            toolTip1.SetToolTip(this.textBoxFileExists3, @"Full file path to file (c:\windows\system32\somefile.dll) and then one of the File: checkboxes must be checked.");
            toolTip1.SetToolTip(this.checkBoxFileExists, @"Checks to see if the file exists at the specified location dir /a /b");
            toolTip1.SetToolTip(this.checkBoxFileExistsSystem, @"Searches the entire c: for the existence of the file. Full filepath is not needed if this is checked.  dir /a /b /s filename");
            toolTip1.SetToolTip(this.checkBoxFileOwner, @"If the file exists, will list the owner of the file.  dir /a /q filepath\filename");
            toolTip1.SetToolTip(this.checkBoxFileCopy, @"If the file exists, the file will be copied into the results directory and will overwrite the file if it exists. (How depends on the confessor method checked).");
            toolTip1.SetToolTip(this.buttonSaveScanConfig, @"Saves the current configuration (username and password are not saved for obvious reasons) to the InvestigationID results directory as 'InvestigationID'.xml and can then be loaded again to set up the same or like scan.");
            toolTip1.SetToolTip(this.buttonLoadScanConfig, @"Load a valid XML file (created with this program) for reuse.");
            toolTip1.SetToolTip(this.checkBoxWMICreateProcess, @"Check this to create a test process on the remot host through WMI.  The test process will stay open so manual closure will be needed.  Useful for testing.");
            toolTip1.SetToolTip(this.textBoxWMICreateProcess, @"WMI will spawn whatever process is listed in this textbox.  Full file path may be required.  See confessor documentation @ http://confessor.codeplex.com for more information on how this might be useful.");
            #endregion
        }

        // Form Checkboxes on how Confessor will run.
        private void checkBoxWMIShares_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxWMIShares.Checked)
            {
                checkBoxWMIFileCopy.Checked = false;
                checkBoxPSExec.Checked = false;
                checkBoxPSExecAsSystem.Checked = false;
            }
            scanObject.WMIShares = checkBoxWMIShares.Checked;
        }
        private void checkBoxWMIFileCopy_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxWMIFileCopy.Checked)
            {
                checkBoxWMIShares.Checked = false;
                checkBoxPSExec.Checked = false;
                checkBoxPSExecAsSystem.Checked = false;
            }
            scanObject.WMIFileCopy = checkBoxWMIFileCopy.Checked;
        }
        private void checkBoxPSExec_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxPSExec.Checked)
            {
                checkBoxWMIShares.Checked = false;
                checkBoxWMIFileCopy.Checked = false;
                checkBoxPSExecAsSystem.Checked = false;
            }
            scanObject.PsExec = checkBoxPSExec.Checked;
        }
        private void checkBoxPSExecAsSystem_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxPSExecAsSystem.Checked)
            {
                checkBoxWMIShares.Checked = false;
                checkBoxWMIFileCopy.Checked = false;
                checkBoxPSExec.Checked = false;
            }
            scanObject.PsExecAsSystem = checkBoxPSExecAsSystem.Checked;
        }


        // Upload file containing IP's and parse through it.
        private void buttonFileUpload_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = Application.StartupPath;
            openFileDialog.Filter = "csv Files(*.csv)|*.csv|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 2;
            openFileDialog.RestoreDirectory = true;

            try
            {
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    xFA.HostsFromFileToArray(scanObject, openFileDialog.FileName);
                    updateNumOfHosts();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }

        }

        // Upload DataGrid IP's manually entered.
        private void buttonDGIPs_Click(object sender, EventArgs e)
        {
            // Verify there is something to scan.
            for (int i = 0; i < dataGridIPs.Rows.Count; i++)
            {
                if (dataGridIPs.Rows[i].Cells[0].Value != null)
                {
                    bool lookLikeIP = xRegEx.RegExTest(4, dataGridIPs.Rows[i].Cells[0].Value.ToString());
                    bool isIP = xRegEx.RegExTest(0, dataGridIPs.Rows[i].Cells[0].Value.ToString());
                    bool isWindowsHost = xRegEx.RegExTest(3, dataGridIPs.Rows[i].Cells[0].Value.ToString());

                    if (lookLikeIP)
                    {
                        if (isIP)
                        {
                            ConfessorHostObject conStat = new ConfessorHostObject();
                            conStat.IP = dataGridIPs.Rows[i].Cells[0].Value.ToString();
                            scanObject.Hosts.Add(conStat);
                        }
                        else
                        {
                            MessageBox.Show(dataGridIPs.Rows[i].Cells[0].Value.ToString() + " is not a valid IP");
                        }
                    }

                    if (isWindowsHost && lookLikeIP == false)
                    {
                        ConfessorHostObject conStat = new ConfessorHostObject();
                        conStat.IP = dataGridIPs.Rows[i].Cells[0].Value.ToString();
                        scanObject.Hosts.Add(conStat);
                    }

                    else if (isWindowsHost == false)
                    {
                        MessageBox.Show(dataGridIPs.Rows[i].Cells[0].Value.ToString() + " is not a valid hostname");
                    }
                }
            }
            updateNumOfHosts();
        }

        // Save Confessor Configuration
        private void buttonSaveScanConfig_Click(object sender, EventArgs e)
        {
            setScanObject();
            xFA.MakeDirectory(scanObject.ResultsDirectory + @"\" + scanObject.InvestigationID);
            xObjectXMLSerializer<ScanObject>.Save(scanObject, scanObject.ResultsDirectory + @"\" + scanObject.InvestigationID + @".xml");
        }

        // Load Confessor Configuration
        private void buttonLoadScanConfig_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = Application.StartupPath;
            openFileDialog.Filter = "xml Files(*.xml)|*.xml|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 2;
            openFileDialog.RestoreDirectory = true;
            try
            {
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    loadConfig(openFileDialog.FileName);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }
        }

        private void setScanObject()
        {
            scanObject.InvestigationID = textBoxInvestigationID.Text;
            scanObject.ConfessorSharePath = textBoxToolsShare.Text;
            scanObject.ResultsSharePath = textBoxResultsShare.Text;
            scanObject.UserName = textBoxUserName.Text;
            scanObject.Password = textBoxPassword.Text;
            scanObject.AllowedMinutesPerHost = (int)numericUpDownMinutesPerHost.Value;
            scanObject.WMITestCreateProcess = checkBoxWMICreateProcess.Checked;
            scanObject.WMICreateProcess = textBoxWMICreateProcess.Text;
            scanObject.WMIShares = checkBoxWMIShares.Checked;
            scanObject.WMIFileCopy = checkBoxWMIFileCopy.Checked;
            scanObject.PsExec = checkBoxPSExec.Checked;
            scanObject.PsExecAsSystem = checkBoxPSExecAsSystem.Checked;
            // Version v.02, results directory has to be in the same location as the confessor executable.  This isn't ideal.
            // scanObject.ResultsDirectory = Application.StartupPath + @"\Results\" + scanObject.InvestigationID;
            // Version v.03 | Adding to allow the results directory to exsit anywhere for WMIShares method....  Need to update document for shares and user permissions.
            scanObject.ResultsDirectory = textBoxResultsShare.Text + @"\" + scanObject.InvestigationID;
            scanObject.customFile1 = textBoxFileExists1.Text;
            scanObject.customFile2 = textBoxFileExists2.Text;
            scanObject.customFile3 = textBoxFileExists3.Text;
            scanObject.customRegKey1 = textBoxRegKey1.Text;
            scanObject.customRegKey2 = textBoxRegKey2.Text;
            scanObject.customRegKey3 = textBoxRegKey3.Text;
            scanObject.FileExists = checkBoxFileExists.Checked;
            scanObject.FileExistsSystem = checkBoxFileExistsSystem.Checked;
            scanObject.FileOwner = checkBoxFileOwner.Checked;
            scanObject.FileCopy = checkBoxFileCopy.Checked;
            scanObject.RegKeyValues = checkBoxRegKeyValues.Checked;
            scanObject.RegKeyCopy = checkBoxRegKeyCopy.Checked;
            //Set up the data grids to show progress of scan.
            dataGridHosts.DataSource = scanObject.Hosts;
            dataGridErrors.DataSource = scanObject.Errors;
            xTreeViewObject.CreateTreeList(treeView1, scanObject);
        }

        private void loadConfig(string path)
        {
            scanObject = xObjectXMLSerializer<ScanObject>.Load(path);
            textBoxInvestigationID.Text = scanObject.InvestigationID;
            textBoxToolsShare.Text = scanObject.ConfessorSharePath;
            textBoxResultsShare.Text = scanObject.ResultsSharePath;
            textBoxUserName.Text = scanObject.UserName;
            textBoxPassword.Text = scanObject.Password;
            numericUpDownMinutesPerHost.Value = scanObject.AllowedMinutesPerHost;
            checkBoxWMICreateProcess.Checked = scanObject.WMITestCreateProcess;
            checkBoxWMIShares.Checked = scanObject.WMIShares;
            checkBoxWMIFileCopy.Checked = scanObject.WMIFileCopy;
            checkBoxPSExec.Checked = scanObject.PsExec;
            checkBoxPSExecAsSystem.Checked = scanObject.PsExecAsSystem;
            textBoxWMICreateProcess.Text = scanObject.WMICreateProcess;
            textBoxFileExists1.Text = scanObject.customFile1;
            textBoxFileExists2.Text = scanObject.customFile2;
            textBoxFileExists3.Text = scanObject.customFile3;
            textBoxRegKey1.Text = scanObject.customRegKey1;
            textBoxRegKey2.Text = scanObject.customRegKey2;
            textBoxRegKey3.Text = scanObject.customRegKey3;
            checkBoxFileExists.Checked = scanObject.FileExists;
            checkBoxFileExistsSystem.Checked = scanObject.FileExistsSystem;
            checkBoxFileOwner.Checked = scanObject.FileOwner;
            checkBoxFileCopy.Checked = scanObject.FileCopy;
            checkBoxRegKeyValues.Checked = scanObject.RegKeyValues;
            checkBoxRegKeyCopy.Checked = scanObject.RegKeyCopy;
            updateNumOfHosts();
            dataGridHosts.DataSource = scanObject.Hosts;
            dataGridErrors.DataSource = scanObject.Errors;
            xTreeViewObject.RestoreTreeList(treeView1, scanObject);
            //treeView1.Refresh();
        }

        // Kicks off the main program, shoves majority of the work to a background worker (seperate thread) to avoid locking the UI.
        // Look into reimplementing multi threading (It has some bugs that need to be worked out, likely solution is to use Locking.)
        private void buttonScan_Click(object sender, EventArgs e)
        {
            // Set scanObject to the form variables.
            setScanObject();

            // useful for testing.  NEED TO DOCUMENT HOW TO TEST WITH THIS CHECKBOX (also document testing with NetCat)
            if (scanObject.WMITestCreateProcess)
            {
                if (scanObject.WMICreateProcess.Length == 0)
                {
                    MessageBox.Show("Tab Test: Create WMI Process has nothing to do.  Enter process to create");
                    return;
                }
            }

            // Check to see if all fields are appropriately filled in.
            if (scanObject.InvestigationID == string.Empty || scanObject.ConfessorSharePath == string.Empty || scanObject.ConfessorSharePath == string.Empty || scanObject.ResultsSharePath == string.Empty || scanObject.UserName == string.Empty || scanObject.Password == string.Empty)
            {
                MessageBox.Show("You must fill out the following fields: Investigation ID, Tool Share Path, Results Share Path, Username, and Password");
                return;
            }
            if (!checkBoxPSExec.Checked && !checkBoxWMIShares.Checked && !checkBoxWMIFileCopy.Checked && !checkBoxPSExecAsSystem.Checked)
            {
                MessageBox.Show("You must check the way you want to scan with Confessor: WMI Shares, WMI Filecopy, PSExec, or PSExec -s (System)");
                return;
            }

            // Check to see if there is something to scan, alert if not.
            if (scanObject.Hosts.Count == 0)
            {
                MessageBox.Show("There is nothing to scan, upload some IP's");
                return;
            }

            // Set Progress Bar Values.
            progressBar.Value = 0;
            progressBar.Maximum = scanObject.Hosts.Count;

            // set up scan directory
            xFA.MakeDirectory(scanObject.ResultsDirectory);

            // Create the Confessor script for this Confessor run, depends on scan type.
            if (scanObject.WMIShares)
            {
                string toolPath = @"%1"; string resultsPath = @"%2";
                BuildConfessorScript.CreateConfessorScript(treeView1, scanObject, toolPath, resultsPath, false);
            }

            if (scanObject.WMIFileCopy || scanObject.PsExec || scanObject.PsExecAsSystem)
            {
                string toolPath = @"c:\CONFESSOR"; string resultsPath = @"c:\CONFESSOR\Results\";
                BuildConfessorScript.CreateConfessorScript(treeView1, scanObject, toolPath, resultsPath, true);
            }

            // If there is data from a config load, clear it for the new run.
            scanObject.Errors.Clear();
            foreach (ConfessorHostObject host in scanObject.Hosts)
            {
                host.HostName = string.Empty;
                host.ScanStartTime = DateTime.MinValue;
                host.ScanFinishedTime = DateTime.MinValue;
                host.ElapsedTime = TimeSpan.Zero;
                host.Status = string.Empty;
            }

            // send to background worker thread for process intensive operation.
            bgWorker.RunWorkerAsync(scanObject);
        }

        private void buttonUnzipResults_Click(object sender, EventArgs e)
        {
            string rootDirectory = string.Empty;
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            folderBrowserDialog.RootFolder = Environment.SpecialFolder.MyComputer; 
            try
            {
                if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
                {
                    rootDirectory = folderBrowserDialog.SelectedPath;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
            }

            string[] directoryArray = System.IO.Directory.GetDirectories(rootDirectory);
            foreach (string dir in directoryArray)
            {
                
            }
        }

        // Update Number of Host label
        private void updateNumOfHosts()
        {
            textBoxHostIPArray.Clear();
            foreach (ConfessorHostObject conf in scanObject.Hosts)
            {
                string p = conf.IP + "\r\n";
                textBoxHostIPArray.Text += p;
            }
            labelNumOfHosts.Text = scanObject.Hosts.Count.ToString();
        }

        private void updateStatusTab()
        {
            dataGridHosts.DataSource = scanObject.Hosts;
            Form.ActiveForm.Refresh();
        }


        #region BG Worker
        // Majority of the work to gather data is performed here and where it calls BuildConfessorScript and Interogation classes.
        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            ScanObject scanObject = (ScanObject)e.Argument;

            // Loop through scanObject.Hosts and connect via WMI to kick of the interogation of the host.
            int y = 0;
            int x = scanObject.Hosts.Count;

            while (y < x)
            {                
                scanErrorsList = interrogation.InitiateInterrogation(scanObject, y);
                y++;
                bgWorker.ReportProgress(y);
            }

            e.Result = scanObject;
        }
        // Update the Progress bar from bgWorker Thread.
        private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar.PerformStep();
            try
            {
                foreach (ScanErrorObject sE in scanErrorsList)
                {
                    scanObject.Errors.Add(new ScanErrorObject() { HostName = sE.HostName, ConfessorFailure = sE.ConfessorFailure, Error = sE.Error });
                }
                scanErrorsList.Clear();
                updateStatusTab();
            }
                //Need to implement logic here that will handle an exception.  Durring long runs the program would have difficulties with this section.
                    // System.NullReferenceException: Object reference not set to an instance of an object.
                    // at Confessor.FormConfessor.updateStatusTab()
                    // at Confessor.FormConfessor.bgWorker_ProgressChanged(Object sender, ProgressChangedEventArgs e)
            catch (Exception ex)
            {
 
            }
        }
        private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            scanObject = (ScanObject)e.Result;
        }
        #endregion


        // Reset the form
        private void buttonReset_Click(object sender, EventArgs e)
        {
            scanObject.Hosts.Clear();
            scanObject.Errors.Clear();
            dataGridIPs.Rows.Clear();
            scanObject.InvestigationID = string.Empty;
            textBoxInvestigationID.Text = string.Empty;
            scanObject.InvestigationID = string.Empty;
            textBoxInvestigationID.Text = string.Empty;
            scanObject.ConfessorSharePath = string.Empty;
            textBoxToolsShare.Text = string.Empty;
            scanObject.ResultsSharePath = string.Empty;
            textBoxResultsShare.Text = string.Empty;
            textBoxHostIPArray.Text = string.Empty;
            textBoxFileOpen.Text = string.Empty;
            labelNumOfHosts.Text = string.Empty;
            checkBoxWMICreateProcess.Checked = false;
            textBoxWMICreateProcess.Text = string.Empty;
        }
        // About the program.  Opens new form displaying information.
        private void labelAbout_Click(object sender, EventArgs e)
        {
            AboutConfessor formAbout = new AboutConfessor();
            formAbout.Show();
        }
        // Close the Confessor program
        private void buttonClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }


    }
}
